package ru.spb.osll.myfit.client.manager;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.rpc.AsyncCallback;
import ru.spb.osll.myfit.client.service.SuiteExecutingService;
import ru.spb.osll.myfit.client.service.SuiteExecutingServiceAsync;
import ru.spb.osll.myfit.client.widget.ExecutingListener;
import ru.spb.osll.myfit.common.ExecutingResult;
import ru.spb.osll.myfit.common.SuiteExecutingResult;
import ru.spb.osll.myfit.common.TestResultMetadataConstants;

import java.util.*;

public class SuiteExecutingManager {

  private static final int TIMER_INTERVAL = 500;

  private final SuiteExecutingServiceAsync m_suiteExecutingService = GWT
          .create(SuiteExecutingService.class);

  private HashMap<String, List<ExecutingListener>> m_listeners = new HashMap<String, List<ExecutingListener>>();

  private final Set<String> m_resultsToListen = new HashSet<String>();

  private Timer m_timer = new Timer() {
    @Override
    public void run() {
      for (String id : m_resultsToListen) {
        processExecutingSuite(id);
      }
    }
  };

  public void executeTestSuite(final List<ExecutingListener> listeners,
                              String id, String comment) {
    TreeMap<String, String> metadata = new TreeMap<String, String>();
    metadata.put(TestResultMetadataConstants.TEST_RUN_COMMENT, comment);
    m_suiteExecutingService.executeSuite(id, metadata,
      new AsyncCallback<SuiteExecutingResult>() {

        @Override
        public void onSuccess(SuiteExecutingResult suiteExecutingResult) {
          for (ExecutingListener listener : listeners) {
            listener.processExecutingResult(suiteExecutingResult);
          }
        }

        @Override
        public void onFailure(Throwable arg0) {

        }
      });
  }

  public void addResultToListen(final SuiteExecutingResult result) {
    if (result != null) {
      String id = result.getId();
      if (m_resultsToListen.size() == 0) {
        m_timer.scheduleRepeating(TIMER_INTERVAL);
      }
      m_resultsToListen.add(id);
    }
  }

  public void addListener(String id, ExecutingListener listener) {
    //todo: check listeners
    List<ExecutingListener> listeners = m_listeners.get(id);
    if (listeners == null) {
      listeners = new LinkedList<ExecutingListener>();
    }
    listeners.add(listener);
    m_listeners.put(id, listeners);
  }

  private void processExecutingSuite(final String id) {
    m_suiteExecutingService.getExecutingResult(id,
      new AsyncCallback<SuiteExecutingResult>() {

        @Override
        public void onFailure(Throwable arg0) {
        }

        @Override
        public void onSuccess(SuiteExecutingResult suiteExecutingResult) {
          if (suiteExecutingResult != null) {
            String id = suiteExecutingResult.getId();
            List<ExecutingListener> listeners = m_listeners.get(id);
            if (suiteExecutingResult.getState() == ExecutingResult.ExecutingState.FINISH) {
              m_resultsToListen.remove(id);
              if (m_resultsToListen.size() == 0) {
                m_timer.cancel();
              }

              for (ExecutingListener listener : listeners) {
                listener.processExecutingResult(suiteExecutingResult);
                listener.finish();
              }

            } else {
              for (ExecutingListener listener : listeners) {
                listener.processExecutingResult(suiteExecutingResult);
              }
            }
          } else {
            m_resultsToListen.remove(id);
            if (m_resultsToListen.size() == 0) {
              m_timer.cancel();
            }
          }
        }
      });
  }
}
